﻿using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;
using YJKRevitBase.Math;
using YJKRevitDimensionText.VerticalAutoDim.Comparer;
using YJKRevitDimensionText.VerticalAutoDim.GeoAlgorithm;
using YJKRevitDimensionText.VerticalAutoDim.GeoModel;
using YJKRevitDimensionText.VerticalAutoDim.GeoTopIntersect;
using YJKRevitDimensionText.VerticalAutoDim.ProgressBar;

namespace YJKRevitDimensionText.VerticalAutoDim.OutWallSearch
{
	internal class OutWallSortAlgorithm
	{
		public List<IPlanarGeo> ArrayWallGeoVisable { get; private set; }

		public List<IPlanarGeo> ArrayWindDoorGeoInOutWallVisable { get; private set; }

		public List<IPlanarGeo> ArrayTopMostGeo { get; private set; }

		public OutWallSortAlgorithm(Autodesk.Revit.DB.Document doc, IList<OutWallData> lstOutWall, Plane plane, Transform transformWcs2Ecs, IDualStatusProgressBarProcess dualStatusProgressBarProcess)
		{
			this.Doc = doc;
			this.ArrayOutWallByViewDirectionAtView = lstOutWall;
			this.ArrayWallGeoVisable = new List<IPlanarGeo>();
			this.TransformWcs2Ecs = transformWcs2Ecs;
			this.Plane = plane;
			this.DualStatusProgressBarProcess = dualStatusProgressBarProcess;
		}

		public void SortOutWallByViewDepth()
		{
			IList<GeoAABB> list = new List<GeoAABB>(this.ArrayOutWallByViewDirectionAtView.Count);
			foreach (OutWallData outWallData in this.ArrayOutWallByViewDirectionAtView)
			{
				IPlanarGeo planarGeo = new BaseWallGeo(outWallData.Element, outWallData.Curve as Line, this.Plane, this.TransformWcs2Ecs);
				planarGeo.Init();
				list.Add(new GeoAABB(planarGeo, outWallData));
			}
			EnumerableExternsion.ForEach<GeoAABB>(((IGeoDepthClippedAlgorithm)new GeoDepthClippedAlgorithm(list, this.DualStatusProgressBarProcess)).GeoDepthClipped(list), delegate(GeoAABB w)
			{
				this.ArrayWallGeoVisable.Add(w.IPlanarGeo);
			});
		}

		public void SortOutWallWindDoorByViewDepth()
		{
			IList<GeoAABB> list = new List<GeoAABB>();
			foreach (IPlanarGeo planarGeo in this.ArrayWallGeoVisable)
			{
				WallGeo wallGeo = (WallGeo)planarGeo;
				Transform transformWcs2Ecs = this.TransformWcs2Ecs;
				Wall wall = wallGeo.Element as Wall;
				IList<ElementId> list2 = wall.FindInserts(false, true, false, true);
				Document document = wall.Document;
				foreach (ElementId elementId in list2)
				{
					FamilyInstance familyInstance = document.GetElement(elementId) as FamilyInstance;
					if (familyInstance != null)
					{
						XYZ xyz = this.TransformWcs2Ecs.OfPoint((familyInstance.Location as LocationPoint).Point);
						if (!MathUtility.LessThan(xyz.X, wallGeo.Min2DPointECS.X) && !MathUtility.GreaterThan(xyz.X, wallGeo.Max2DPointECS.X))
						{
							IPlanarGeo planarGeo2 = null;
							int integerValue = familyInstance.Category.Id.IntegerValue;
							if (integerValue != -2000023)
							{
								if (integerValue == -2000014)
								{
									planarGeo2 = new WindowGeo(familyInstance, this.Plane, this.TransformWcs2Ecs);
								}
							}
							else
							{
								planarGeo2 = new DoorGeo(familyInstance, this.Plane, this.TransformWcs2Ecs);
							}
							if (planarGeo2 != null)
							{
								planarGeo2.Init();
								GeoAABB item = new GeoAABB(planarGeo2, null);
								list.Add(item);
							}
						}
					}
				}
			}
			IList<GeoAABB> list3 = new List<GeoAABB>(this.ArrayWallGeoVisable.Count);
			foreach (IPlanarGeo iPlanarGeo in this.ArrayWallGeoVisable)
			{
				list3.Add(new GeoAABB(iPlanarGeo, null));
			}
			IList<GeoAABB> source = ((IGeoDepthClippedAlgorithm)new WindDoorGeoDepthClippedAlgorithm(list3, this.DualStatusProgressBarProcess)).GeoDepthClipped(list);
			this.ArrayWindDoorGeoInOutWallVisable = (from e in source
			select e.IPlanarGeo).ToList<IPlanarGeo>();
		}

		public bool CreatePlanarGeo()
		{
			try
			{
				if (this.ArrayWallGeoVisable.Count == 0)
				{
					return false;
				}
				this.ArrayWallGeoVisable.Sort(new GeoComparerByTopLevel(true));
				List<Element> list = new List<Element>();
				list.Add(this.ArrayWallGeoVisable.First<IPlanarGeo>().Element);
				for (int i = 1; i < this.ArrayWallGeoVisable.Count; i++)
				{
					Element element = this.ArrayWallGeoVisable[i].Element;
					if (list[0].Id.IntegerValue == element.Id.IntegerValue)
					{
						list.Add(element);
					}
				}
				IList<IPlanarGeo> collection = new GeoTopIntersectManager(this.Doc, this.Plane, this.TransformWcs2Ecs).CreateGeoTopIntersect(list);
				this.ArrayTopMostGeo = new List<IPlanarGeo>(collection);
				foreach (IPlanarGeo planarGeo in this.ArrayWallGeoVisable)
				{
					if (list.Contains(planarGeo.Element))
					{
						this.ArrayTopMostGeo.Add(planarGeo);
					}
				}
				return true;
			}
			catch
			{
			}
			return false;
		}

		public bool GetTopGeo(XYZ ptMaxRegion, XYZ ptMinRegion)
		{
			try
			{
				if (ptMaxRegion == null || ptMinRegion == null || this.ArrayWallGeoVisable.Count == 0)
				{
					return false;
				}
				this.ArrayTopMostGeo = new List<IPlanarGeo>();
				List<IPlanarGeo> wallGeoByRegion = this.GetWallGeoByRegion(ptMaxRegion, ptMinRegion, true);
				if (wallGeoByRegion.Count != 0)
				{
					this.GetTopMostGeo(wallGeoByRegion);
				}
				wallGeoByRegion.Clear();
				wallGeoByRegion = this.GetWallGeoByRegion(ptMaxRegion, ptMinRegion, false);
				if (wallGeoByRegion.Count != 0)
				{
					this.GetTopMostGeo(wallGeoByRegion);
				}
				return true;
			}
			catch
			{
			}
			return false;
		}

		private List<IPlanarGeo> GetWallGeoByRegion(XYZ ptMaxRegion, XYZ ptMinRegion, bool bByLeft = true)
		{
			List<IPlanarGeo> result;
			try
			{
				XYZ xyz = (ptMaxRegion + ptMinRegion) / 2.0;
				xyz = this.TransformWcs2Ecs.OfPoint(xyz);
				List<IPlanarGeo> list = new List<IPlanarGeo>();
				foreach (IPlanarGeo planarGeo in this.ArrayWallGeoVisable)
				{
					if (bByLeft)
					{
						if (MathUtility.LessThan(planarGeo.Min2DPointECS.X, xyz.X, 1E-06))
						{
							list.Add(planarGeo);
						}
					}
					else if (MathUtility.GreaterThan(planarGeo.Max2DPointECS.X, xyz.X, 1E-06))
					{
						list.Add(planarGeo);
					}
				}
				result = list;
			}
			catch (Exception ex)
			{
				throw ex;
			}
			return result;
		}

		private void GetTopMostGeo(List<IPlanarGeo> lstWalls)
		{
			try
			{
				if (lstWalls.Count != 0)
				{
					List<Element> lstWallElems = new List<Element>();
					lstWalls.ForEach(delegate(IPlanarGeo e)
					{
						lstWallElems.Add(e.Element);
					});
					IList<IPlanarGeo> list = new GeoTopIntersectManager(this.Doc, this.Plane, this.TransformWcs2Ecs).CreateGeoTopIntersect(lstWallElems);
					if (list.Count != 0)
					{
						EnumerableExternsion.ForEach<IPlanarGeo>(list, delegate(IPlanarGeo e)
						{
							if (!this.ArrayTopMostGeo.Contains(e))
							{
								this.ArrayTopMostGeo.Add(e);
							}
						});
					}
					lstWalls.Sort(new GeoComparerByTopLevel(true));
					List<IPlanarGeo> list2 = new List<IPlanarGeo>();
					list2.Add(lstWalls.First<IPlanarGeo>());
					for (int i = 1; i < lstWalls.Count; i++)
					{
						IPlanarGeo planarGeo = lstWalls[i];
						if (list2[0].Element.Id.IntegerValue == planarGeo.Element.Id.IntegerValue)
						{
							list2.Add(planarGeo);
						}
					}
					list2.ForEach(delegate(IPlanarGeo e)
					{
						if (!this.ArrayTopMostGeo.Contains(e))
						{
							this.ArrayTopMostGeo.Add(e);
						}
					});
				}
			}
			catch
			{
			}
		}

		private readonly Document Doc;

		private readonly Plane Plane;

		private readonly Transform TransformWcs2Ecs;

		private readonly IDualStatusProgressBarProcess DualStatusProgressBarProcess;

		private readonly IList<OutWallData> ArrayOutWallByViewDirectionAtView;
	}
}
